home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 May / EnigmA AMIGA RUN 18 (1997)(G.R. Edizioni)(IT)[!][issue 1997-05][EAR-CD II].iso / ghost / gs403src_gs.lha / gs4.03 / gs_setpd.ps < prev    next >
Text File  |  1996-09-02  |  20KB  |  629 lines

  1. %    Copyright (C) 1994, 1996 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % The current implementation of setpagedevice has the following limitations:
  16. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  17.  
  18. languagelevel 1 .setlanguagelevel
  19. level2dict begin
  20.  
  21. % ---------------- Redefinitions ---------------- %
  22.  
  23. % Redefine .beginpage and .endpage so that they call BeginPage and
  24. % EndPage respectively if appropriate.
  25.  
  26. /.beginpage
  27.  { .currentshowpagecount
  28.     { .currentpagedevice pop /BeginPage .knownget { exec } { pop } ifelse }
  29.    if
  30.  } bind odef
  31.  
  32. /.endpage
  33.  { .currentshowpagecount
  34.     { exch .currentpagedevice pop /EndPage .knownget
  35.        { exec }
  36.        { exch pop 2 ne }
  37.       ifelse
  38.     }
  39.     { 2 ne
  40.     }
  41.    ifelse
  42.  } bind odef
  43.  
  44. % Define interpreter callouts for handling gstate-saving operators,
  45. % to make sure that they create a page device dictionary for use by
  46. % the corresponding gstate-restoring operator.
  47. % We'd really like to avoid the cost of doing this, but we don't see how.
  48. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  49. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  50. % interpreter.
  51.  
  52. (%gsavepagedevice) cvn
  53.  { currentpagedevice pop gsave
  54.  } bind def
  55.  
  56. (%savepagedevice) cvn
  57.  { currentpagedevice pop save
  58.  } bind def
  59.  
  60. (%gstatepagedevice) cvn
  61.  { currentpagedevice pop gstate
  62.  } bind def
  63.  
  64. (%copygstatepagedevice) cvn
  65.  { currentpagedevice pop copy
  66.  } bind def
  67.  
  68. (%currentgstatepagedevice) cvn
  69.  { currentpagedevice pop currentgstate
  70.  } bind def
  71.  
  72. % Define interpreter callouts for handling gstate-restoring operators
  73. % when the current page device needs to be changed.
  74. % The names %grestorepagedevice, %grestoreallpagedevice,
  75. % %restorepagedevice, and %setgstatepagedevice are known to the interpreter.
  76.  
  77. /.installpagedevice
  78.  {    % Since setpagedevice doesn't create new device objects,
  79.     % we must (carefully) reinstall the old parameters in
  80.     % the same device.
  81.    .currentpagedevice pop null currentdevice null .trysetparams
  82.    dup type /booleantype eq
  83.     { pop pop }
  84.     {        % This should never happen!
  85.       DEBUG { (Error in .trysetparams!\n) print pstack flush } if
  86.       cleartomark pop pop pop
  87.       /.installpagedevice cvx /rangecheck signalerror
  88.     }
  89.    ifelse pop pop
  90.    erasepage initgraphics .beginpage
  91.  } bind def
  92.  
  93. /.uninstallpagedevice
  94.  { 2 .endpage { .currentnumcopies false .outputpage } if
  95.    nulldevice
  96.  } bind def
  97.  
  98. (%grestorepagedevice) cvn
  99.  { .uninstallpagedevice grestore .installpagedevice
  100.  } bind def
  101.  
  102. (%grestoreallpagedevice) cvn
  103.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  104.  } bind def
  105.  
  106. (%restorepagedevice) cvn
  107.  { .uninstallpagedevice grestore .installpagedevice restore
  108.  } bind def
  109.  
  110. (%setgstatepagedevice) cvn
  111.  { .uninstallpagedevice setgstate .installpagedevice
  112.  } bind def
  113.  
  114. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  115. /.numcopiesdict mark
  116.   /NumCopies dup
  117. .dicttomark readonly def
  118.  
  119. /.currentnumcopies
  120.  { currentdevice //.numcopiesdict .getdeviceparams
  121.    dup type /integertype eq
  122.     { exch pop exch pop }
  123.     { cleartomark #copies }
  124.    ifelse
  125.  } bind odef
  126.  
  127. % ---------------- Auxiliary definitions ---------------- %
  128.  
  129. % Define the required attributes of all page devices, and their default values.
  130. % We don't include attributes such as .MediaSize, which all devices
  131. % are guaranteed to supply on their own.
  132. /.defaultpolicies mark
  133.   /PolicyNotFound 1
  134.   /PageSize 0
  135.   /PolicyReport {pop} bind
  136. .dicttomark readonly def
  137. /.requiredattrs mark
  138.   /PageOffset [0 0] readonly
  139. % We define InputAttributes and OutputAttributes with a single
  140. % dummy media type that handles pages of any size.
  141. % Devices that care will override this.
  142.   /InputAttributes mark 0
  143.     mark /PageSize [0 dup 16#7ffff dup] .dicttomark readonly
  144.   .dicttomark readonly
  145.   (%MediaSource) 0
  146.   /OutputAttributes mark 0
  147.     mark .dicttomark readonly
  148.   .dicttomark readonly
  149.   (%MediaDestination) 0
  150.   /Install {.callinstall} bind
  151.   /BeginPage {.callbeginpage} bind
  152.   /EndPage {.callendpage} bind
  153.   /Policies .defaultpolicies
  154. .dicttomark readonly def
  155.  
  156. % Define currentpagedevice so it creates the dictionary on demand if needed,
  157. % adding all the required entries defined just above.
  158. % We have to deal specially with entries that the driver may change
  159. % on its own.
  160. /.dynamicppkeys mark
  161.   /.MediaSize dup        % because it changes when PageSize is set
  162.   /PageCount dup
  163. .dicttomark readonly def
  164. /.makecurrentpagedevice        % - .makecurrentpagedevice <dict>
  165.  { currentdevice null .getdeviceparams
  166.     % In case of duplicate keys, .dicttomark takes the entry
  167.     % lower on the stack, so we can just append the defaults here.
  168.    .requiredattrs { } forall .dicttomark
  169.    dup .setpagedevice
  170.  } bind def
  171. /currentpagedevice
  172.  { .currentpagedevice
  173.     { dup length 0 eq
  174.        { pop .makecurrentpagedevice
  175.        }
  176.        {    % If any of the dynamic keys have changed,
  177.         % we must update the page device dictionary.
  178.      currentdevice //.dynamicppkeys .getdeviceparams .dicttomark
  179.       {    % Stack: current key value
  180.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  181.          { 2 index wcheck not
  182.         {    % This is the first entry being updated.
  183.             % Copy the dictionary to make it writable.
  184.           3 -1 roll dup length dict .copydict
  185.           3 1 roll
  186.         }
  187.            if
  188.            2 index 3 1 roll put
  189.          }
  190.          { pop pop
  191.          }
  192.         ifelse
  193.       }
  194.      forall
  195.         % We would like to do a .setpagedevice so we don't keep
  196.         % re-creating the dictionary.  Unfortunately, the effect
  197.         % of this is that if any dynamic key changes (PageCount
  198.         % in particular), we will do the equivalent of a
  199.         % setpagedevice at the next restore or grestore.
  200.         % Therefore, we make the dictionary read-only, but
  201.         % we don't store it away.  I.e., NOT:
  202.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  203.      readonly
  204.        }
  205.       ifelse
  206.     }
  207.    if
  208.  } bind odef
  209.  
  210. % The implementation of setpagedevice is quite complex.  Currently,
  211. % everything but the media matching algorithm is implemented here.
  212.  
  213. % By default, we only present the requested changes to the device,
  214. % but there are some parameters that require special merging action.
  215. % Define those parameters here, with the procedures that do the merging.
  216. % The procedures are called as follows:
  217. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  218. /.mergespecial mark
  219.   /InputAttributes
  220.    { dup null eq
  221.       { pop null
  222.       }
  223.       { 3 copy pop .knownget
  224.      { dup null eq
  225.         { pop dup length dict }
  226.         { dup length 2 index length add dict .copydict }
  227.        ifelse
  228.      }
  229.      { dup length dict
  230.      }
  231.         ifelse .copydict readonly
  232.       }
  233.      ifelse
  234.    } bind
  235.   /OutputAttributes 1 index
  236.   /Policies
  237.     { 3 copy pop .knownget
  238.        { dup length 2 index length add dict .copydict }
  239.        { dup length dict }
  240.       ifelse copy readonly
  241.     } bind
  242. .dicttomark readonly def
  243.  
  244. % Define the keys used in input attribute matching.
  245. /.inputattrkeys [
  246.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  247. ] readonly def
  248. % Define other keys used in media selection.
  249. /.inputselectionkeys [
  250.   /MediaPosition /Orientation
  251. ] readonly def
  252.  
  253. % Define the keys used in output attribute matching.
  254. /.outputattrkeys [
  255.   /OutputType
  256. ] readonly def
  257.  
  258. % Define all the parameters that should always be copied to the merged
  259. % dictionary.
  260. /.copiedkeys [
  261.   /OutputDevice
  262.   .mergespecial { pop } forall
  263.   .inputattrkeys aload pop
  264.   .inputselectionkeys aload pop
  265.   .outputattrkeys aload pop
  266. ] readonly def
  267.  
  268. % Define the parameters that should not be presented to the device.
  269. % The procedures are called as follows:
  270. %    <merged> <key> <value> -proc-
  271. % The procedure leaves all its operands on the stack and returns
  272. % true iff the key/value pair should be presented to .putdeviceparams.
  273. /.presentspecial mark
  274.   .dynamicppkeys { pop false } forall
  275.             % We must ignore an explicit request for .MediaSize,
  276.             % because media matching always handles this.
  277.   /.MediaSize false
  278.   /Name false
  279.   /OutputDevice false
  280.   /PageOffset false
  281.   /PageSize false        % obsolete alias for .MediaSize
  282.   /InputAttributes false
  283.   .inputattrkeys
  284.     { dup /PageSize eq
  285.        { pop }
  286.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  287.       ifelse
  288.     }
  289.   forall
  290.   .inputselectionkeys { false } forall
  291.   /OutputAttributes false
  292.   .outputattrkeys
  293.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  294.   forall
  295.   /Install false
  296.   /BeginPage false
  297.   /EndPage false
  298.   /Policies false
  299.     % Our extensions:
  300.   /HWColorMap
  301.     {            % HACK: don't transmit the color map, because
  302.             % window systems can change the color map on their own
  303.             % incrementally.  Someday we'll have a better
  304.             % solution for this....
  305.       false
  306.     }
  307.   /ViewerPreProcess false
  308. .dicttomark readonly def
  309.  
  310. % Define access to device defaults.
  311. /.defaultdeviceparams
  312.  { finddevice null .getdeviceparams
  313.  } bind def
  314.  
  315. % Select media (input or output).  The hard work is done in an operator:
  316. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  317. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  318. %    <pagedict> null <policydict> <keys> .matchmedia null true
  319. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  320.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  321.             %   .selectmedia
  322.  { 5 index 5 -2 roll 4 index .matchmedia
  323.         % Stack: orig request merged failed attrkeys mediakey
  324.         %   (key true | false)
  325.     { 4 index 3 1 roll put pop
  326.     }
  327.     {    % Adobe's implementations have a "big hairy heuristic"
  328.     % to choose the set of keys to report as having failed the match.
  329.     % For the moment, we report any keys that are in the request
  330.     % and don't have the same value as in the original dictionary.
  331.       5 index 1 index .knownget
  332.        { 4 index 3 1 roll put }
  333.        { 3 index exch .undef }
  334.       ifelse
  335.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  336.      3 index 1 index .knownget
  337.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  338.       { true }
  339.      ifelse        % Stack: ... <failed> <attrkey> <report>
  340.       { 2 copy /rangecheck put }
  341.      if pop
  342.        }
  343.       forall
  344.     }
  345.    ifelse
  346.  } bind def
  347.  
  348. % Apply Policies to any unprocessed failed requests.
  349. % As we process each request entry, we replace the error name
  350. % in the <failed> dictionary with the policy value,
  351. % and we replace the key in the <merged> dictionary with its prior value
  352. % (or remove it if it had no prior value).
  353. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  354.             %   <orig> <merged'> <failed'>
  355.  { 1 index /Policies get 1 index
  356.     { type /integertype eq
  357.        { pop        % already processed
  358.        }
  359.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  360.             % Stack: <orig> <merged> <failed> <Policies> <key>
  361.             %   <policy>
  362.      dup 1 ne
  363.       {    % Set errorinfo and signal a configurationerror.
  364.         % Note that we currently treat all Policy values other than 1
  365.         % the same as 0.
  366.         pop dup 4 index exch get 2 array astore
  367.         $error /errorinfo 3 -1 roll put
  368.         cleartomark
  369.         /setpagedevice load /configurationerror signalerror
  370.       }
  371.       {    % Roll back the failed request to its previous status.
  372. DEBUG { (Rolling back.\n) print pstack flush } if
  373.         3 index 2 index 3 -1 roll put
  374.         4 index 1 index .knownget
  375.          { 4 index 3 1 roll put }
  376.          { 3 index exch .undef }
  377.         ifelse
  378.       }
  379.      ifelse
  380.        }
  381.       ifelse
  382.     }
  383.    forall pop
  384.  } bind def
  385.  
  386. % Prepare to present parameters to the device, by spreading them onto the
  387. % operand stack and removing any that shouldn't be presented.
  388. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  389.  { mark exch dup
  390.     {            % Stack: -mark- key1 value1 ... merged key value
  391.       .presentspecial 2 index .knownget
  392.        { exec { 3 -1 roll } { pop pop } ifelse }
  393.        { 3 -1 roll }
  394.       ifelse
  395.     }
  396.    forall pop
  397.  } bind def
  398.  
  399. % Put device parameters without resetting currentpagedevice.
  400. % (.putdeviceparams clears the current page device.)
  401. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  402.             %   <key1> <value1> ... .putdeviceparamsonly
  403.             % On success: <device> <eraseflag>
  404.             % On failure: <device> <Policies|null> <req_all> -mark-
  405.             %   <key1> <error1> ...
  406.  { .currentpagedevice
  407.     { counttomark 4 add 1 roll .putdeviceparams
  408.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  409.       .setpagedevice
  410.     }
  411.     { pop .putdeviceparams
  412.     }
  413.    ifelse
  414.  } bind def
  415.  
  416. % Try setting the device parameters from the merged request.
  417. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  418.             %   .trysetparams
  419.  { true 4 index .prepareparams
  420.             % Add the computed .MediaSize.
  421.             % Stack: merged (ignored) device Policies -true-
  422.             %   -mark- key1 value1 ...
  423.    counttomark 5 add index .computemediasize
  424.    exch pop exch pop /.MediaSize exch
  425. DEBUG { (Putting.\n) print pstack flush } if
  426.    .putdeviceparamsonly
  427. DEBUG { (Result of putting.\n) print pstack flush } if
  428.  } bind def
  429.  
  430. % Compute the media size and initial matrix from a merged request (after
  431. % media selection).
  432. /.computemediasize    % <request> .computemediasize
  433.             %   <request> <matrix> <[width height]>
  434.  { dup /PageSize get                    % requested page size
  435.    1 index /InputAttributes get
  436.      2 index (%MediaSource) get get /PageSize get    % media size
  437.                             % (may be a range)
  438.    2 index /Policies get
  439.      dup /PageSize .knownget
  440.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  441.                             % affects scaling
  442.    3 index /Orientation .knownget not { null } if
  443.    matrix .matchpagesize pop        % (can't fail)
  444.    2 array astore
  445.  } bind def
  446.  
  447. % ---------------- setpagedevice itself ---------------- %
  448.  
  449. /setpagedevice
  450.  { mark exch currentpagedevice
  451.  
  452.         % Check whether we are changing OutputDevice;
  453.         % also handle the case where the current device
  454.         % is not a page device.
  455.         % Stack: mark <request> <current>
  456. DEBUG { (Checking.\n) print pstack flush } if
  457.  
  458.    dup /OutputDevice .knownget
  459.     {        % Current device is a page device.
  460.       2 index /OutputDevice .knownget
  461.        {    % A specific OutputDevice was requested.
  462.      2 copy eq
  463.       { pop pop null }
  464.       { exch pop }
  465.      ifelse
  466.        }
  467.        { pop null
  468.        }
  469.       ifelse
  470.     }
  471.     {        % Current device is not a page device.
  472.         % Use the default device.
  473.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  474.     }
  475.    ifelse
  476.    dup null eq
  477.     { pop
  478.     }
  479.     { exch pop .defaultdeviceparams
  480.         % In case of duplicate keys, .dicttomark takes the entry
  481.         % lower on the stack, so we can just append the defaults here.
  482.       .requiredattrs { } forall .dicttomark
  483.     }
  484.    ifelse
  485.  
  486.         % Check whether a viewer wants to intervene.
  487.         % We must check both the request (which takes precedence)
  488.         % and the current dictionary.
  489.         % Stack: mark <request> <orig>
  490.    exch dup /ViewerPreProcess .knownget
  491.     { exec }
  492.     { 1 index /ViewerPreProcess .knownget { exec } if }
  493.    ifelse exch
  494.  
  495.         % Construct a merged request from the actual request plus
  496.         % any keys that should always be propagated.
  497.         % Stack: mark <request> <orig>
  498. DEBUG { (Merging.\n) print pstack flush } if
  499.  
  500.    exch 1 index length 1 index length add dict
  501.    .copiedkeys
  502.     {        % Stack: <orig> <request> <merged> <key>
  503.       3 index 1 index .knownget { 3 copy put pop } if pop
  504.     }
  505.    forall
  506.         % Stack: <orig> <request> <merged>
  507.    dup 2 index
  508.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  509.       .mergespecial 2 index .knownget { exec } if
  510.       put dup
  511.     }
  512.    forall pop
  513.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  514.         % change HWResolution.
  515.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  516.  
  517.         % Select input and output media.
  518.         % Stack: mark <orig> <request> <merged>
  519. DEBUG { (Selecting.\n) print pstack flush } if
  520.  
  521.    0 dict    % <failed>
  522.    1 index /InputAttributes .knownget
  523.     { 2 index /Policies get
  524.       .inputattrkeys (%MediaSource) cvn .selectmedia
  525.     } if
  526.    1 index /OutputAttributes .knownget
  527.     { 2 index /Policies get
  528.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  529.      } if
  530.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  531.    .applypolicies
  532.    3 -1 roll 4 1 roll        % swap back
  533.  
  534.         % Construct the new device, and attempt to set its attributes.
  535.         % Stack: mark <orig> <request> <merged> <failed>
  536. DEBUG { (Constructing.\n) print pstack flush } if
  537.  
  538.    currentdevice .devicename 2 index /OutputDevice get eq
  539.     { currentdevice }
  540.     { 1 index /OutputDevice get finddevice }
  541.    ifelse
  542.         %**************** We should copy the device here,
  543.         %**************** but since we can't close the old device,
  544.         %**************** we don't.  This is WRONG.
  545.     %****************copydevice
  546.    2 index /Policies get
  547.    .trysetparams
  548.    dup type /booleantype ne
  549.     {        % The request failed.
  550.         % Stack: ... <orig> <request> <merged> <failed> <device>
  551.         %   <Policies> true mark <name> <errorname> ...
  552. DEBUG { (Recovering.\n) print pstack flush } if
  553.       counttomark 4 add index
  554.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  555.       pop pop pop
  556.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  557.         %   <Policies>
  558.       6 2 roll 3 -1 roll 4 1 roll
  559.       .applypolicies
  560.       3 -1 roll 4 1 roll 6 -2 roll
  561.       .trysetparams        % shouldn't fail!
  562.       dup type /booleantype ne
  563.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  564.          /setpagedevice load exch signalerror
  565.        }
  566.       if
  567.     }
  568.    if
  569.  
  570.         % The attempt succeeded.  Install the new device.
  571.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  572. DEBUG { (Installing.\n) print pstack flush } if
  573.  
  574.    pop 2 .endpage
  575.     { 1 true .outputpage
  576.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  577.     }
  578.    if
  579.         % .setdevice clears the current page device!
  580.    .currentpagedevice pop exch
  581.    .setdevice pop
  582.    .setpagedevice
  583.  
  584.         % Merge the request into the current page device.
  585.         % Stack: mark ... <merged> <failed>
  586.    exch currentpagedevice dup length 2 index length add dict
  587.    .copydict .copydict
  588.         % Initialize the default matrix, taking media matching
  589.         % into account.
  590.    .computemediasize pop initmatrix concat
  591.    dup /PageOffset .knownget
  592.     {        % Translate by the given number of 1/72" units in device X/Y.
  593.       dup 0 get exch 1 get
  594.       2 index /HWResolution get dup 1 get exch 0 get
  595.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  596.       idtransform translate
  597.     }
  598.    if
  599.         % We must install the new page device dictionary
  600.         % before calling the Install procedure.
  601.    dup .setpagedevice
  602.    .setdefaultscreen    % Set the default screen before calling Install.
  603.    dup /Install .knownget { exec } if
  604.    matrix currentmatrix .setdefaultmatrix
  605.         % Erase and initialize the page.
  606.    erasepage initgraphics
  607.    .beginpage
  608.  
  609.         % Clean up, calling PolicyReport if needed.
  610.         % Stack: mark ... <failed> <merged>
  611. DEBUG { (Finishing.\n) print pstack flush } if
  612.  
  613.    exch dup length 0 ne
  614.     { 1 index /Policies get /PolicyReport get
  615.       counttomark 1 add 2 roll cleartomark
  616.       exec
  617.     }
  618.     { cleartomark
  619.     }
  620.    ifelse
  621.  
  622.  } odef
  623.  
  624. end                % level2dict
  625. .setlanguagelevel
  626.